using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using Oracle.ManagedDataAccess.Client;
using Oracle.ManagedDataAccess.Types;
using OracleInternal.Common;
using OracleInternal.ServiceObjects;

namespace OracleInternal.BinXml
{
	internal class ObxmlDecodeStream : ObxmlDecoder, IDisposable
	{
		private int m_CountDecoded;

		private bool m_bInitStreaming;

		private byte[] m_RawDecodedText;

		private ObxmlDecodeResponse m_DecodeResponse;

		private long m_InputLength = -1L;

		private OracleBlob m_Blob;

		private byte[] m_CsxBuffer;

		private long m_CsxOffset = -1L;

		private int m_TextBufferOffset;

		private bool m_IsLastSubstring;

		private bool m_Disposed;

		internal static readonly int DefaultChunkSize = 5;

		internal static readonly int DefaultTextBufferSize = 16384;

		internal new bool IsValid => base.IsValid;

		internal long CountDecoded => m_CountDecoded;

		internal string DecodedText
		{
			get;
			set;
		}

		internal ObxmlDecodeStream()
		{
			ResetRequestObject();
			m_CountDecoded = 0;
			base.TokenMap = null;
			m_InputLength = 0L;
			m_DecodeResponse = null;
		}

		internal ObxmlDecodeStream(ObxmlDecodeContext decodeContext, OracleBlob blob)
		{
			ResetRequestObject(decodeContext, blob);
		}

		internal ObxmlDecodeStream ResetRequestObject(ObxmlDecodeContext decodeContext, OracleBlob blob)
		{
			ResetRequestObject();
			m_CountDecoded = 0;
			SetDecodeContext(decodeContext);
			m_Blob = blob;
			m_InputLength = 0L;
			m_DecodeResponse = null;
			return this;
		}

		internal int ReadBlob(OracleBlobImpl blobImpl, byte[] buffer, int offset, int count)
		{
			try
			{
				if (offset < 0)
				{
					throw new ArgumentOutOfRangeException("offset");
				}
				if (count < 0)
				{
					throw new ArgumentOutOfRangeException("count");
				}
				if (offset + count > buffer.Length)
				{
					throw new ArgumentOutOfRangeException("count");
				}
				if (count == 0 || (blobImpl.m_isTemporaryLob && !blobImpl.m_doneTempLobCreate))
				{
					return 0;
				}
				long locatorOffset = 1L;
				long num = 0L;
				num = ((count + offset > buffer.Length) ? (buffer.Length - offset) : count);
				return (int)blobImpl.Read(locatorOffset, num, offset, ref buffer);
			}
			catch (Exception)
			{
				throw;
			}
		}

		private byte[] ReadBlob(OracleBlobImpl blobImpl)
		{
			byte[] array = null;
			long length = blobImpl.GetLength();
			int num = 0;
			num = (int)((length < int.MaxValue) ? length : int.MaxValue);
			array = new byte[num];
			ReadBlob(blobImpl, array, 0, num);
			return array;
		}

		internal bool Open(ObxmlDecodeContext decodeContext, byte[] encodedCSX, int inputLength)
		{
			m_InputLength = inputLength;
			m_CsxBuffer = encodedCSX;
			SetDecodeContext(decodeContext);
			if (base.IsValid)
			{
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.InvalidArguments));
			}
			m_RawDecodedText = new byte[DefaultTextBufferSize];
			SetRequestObject(isFullDecode: false, m_CsxOffset, m_CsxBuffer, (int)m_InputLength, m_TextBufferOffset, m_RawDecodedText, outputOwnedByClient: false, DefaultTextBufferSize);
			return m_bInitStreaming = true;
		}

		public new void Dispose()
		{
			Close();
		}

		~ObxmlDecodeStream()
		{
			Dispose(disposing: false);
		}

		internal override bool ResetDecodeState(bool disposing)
		{
			m_CountDecoded = 0;
			m_RawDecodedText = null;
			m_DecodeResponse = null;
			m_InputLength = -1L;
			m_Blob = null;
			m_CsxBuffer = null;
			m_CsxOffset = -1L;
			m_TextBufferOffset = 0;
			m_IsLastSubstring = false;
			m_bInitStreaming = false;
			m_IsLastSubstring = false;
			m_Disposed = false;
			return base.ResetDecodeState(disposing);
		}

		protected new virtual void Dispose(bool disposing)
		{
			try
			{
				if (!m_Disposed)
				{
					if (disposing)
					{
						base.Dispose();
					}
					m_CountDecoded = 0;
					m_RawDecodedText = null;
					m_Blob = null;
					m_TextBufferOffset = 0;
					if (m_bInitStreaming)
					{
						m_DecodeResponse = null;
						m_InputLength = 0L;
						m_CsxBuffer = null;
						m_CsxOffset = -1L;
						m_bInitStreaming = false;
						m_IsLastSubstring = false;
					}
					m_Disposed = true;
				}
			}
			catch
			{
			}
		}

		internal bool Close()
		{
			bool bInitStreaming = m_bInitStreaming;
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
			return bInitStreaming;
		}

		internal string DecodeNext(int numCharsRequested)
		{
			if (!m_bInitStreaming)
			{
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.NotOpenForStreaming));
			}
			base.RequestObject.TextLengthRequested = numCharsRequested;
			base.RequestObject.EncodedContent.ReadOffset = m_CsxOffset;
			base.RequestObject.m_RequestOutput.WriteOffset = 0L;
			if (m_DecodeResponse != null)
			{
				base.RequestObject.EncodedContent.ReadOffset = m_DecodeResponse.CurrentOffset;
			}
			else
			{
				base.RequestObject.EncodedContent.ReadOffset = 0L;
			}
			m_DecodeResponse = Decode_New(base.RequestObject);
			if (m_IsLastSubstring)
			{
				return string.Empty;
			}
			if (m_DecodeResponse.ErrorType == ObxmlErrorTypes.Done)
			{
				m_IsLastSubstring = true;
			}
			else if (!m_DecodeResponse.IsSuccess)
			{
				return null;
			}
			_ = Encoding.Default;
			DecodedText = string.Empty;
			m_CountDecoded = (int)m_DecodeResponse.DecodedTextLength;
			string @string = Encoding.Default.GetString(m_DecodeResponse.OutputBuffer, 0, m_CountDecoded);
			if (m_CountDecoded <= 0)
			{
				return string.Empty;
			}
			return DecodedText = @string;
		}

		private int Decode(byte[] textBuffer, int numCharsToDecode, long textBufferOffset, long csxOffset)
		{
			base.RequestObject.m_RequestOutput.SetObxmlOutputObject(textBuffer, textBufferOffset);
			base.RequestObject.TextLengthRequested = numCharsToDecode;
			base.RequestObject.EncodedContent.ReadOffset = csxOffset;
			return (int)Decode_New(base.RequestObject).DecodedTextLength;
		}

		internal string Decode(byte[] buffer, int inputLength, int numCharsRequested)
		{
			if (!IsValid)
			{
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.InvalidArguments));
			}
			m_InputLength = inputLength;
			m_RawDecodedText = new byte[numCharsRequested];
			SetRequestObject(isFullDecode: false, m_CsxOffset, buffer, (int)m_InputLength, m_TextBufferOffset, m_RawDecodedText, outputOwnedByClient: false, numCharsRequested);
			_ = Encoding.Default;
			DecodedText = string.Empty;
			m_CountDecoded = 0;
			int num = 0;
			StringBuilder stringBuilder = new StringBuilder(ObxmlDecodeContext.GetOutputLengthEstimate(buffer.Length, fullBufferEstimate: true));
			while ((num = Decode(m_RawDecodedText, numCharsRequested, m_TextBufferOffset, m_CsxOffset)) != 0)
			{
				int charsConverted = 0;
				ObxmlStream.Unicode_AL16UTF16_CHARSET.ConvertBytesToStringSB(stringBuilder, m_RawDecodedText, 0, num, ref charsConverted);
				m_CountDecoded += num;
				if (num <= 0)
				{
					break;
				}
			}
			DecodedText = stringBuilder.ToString();
			return DecodedText;
		}

		internal string Decode(byte[] buffer, int inputLength)
		{
			if (!IsValid)
			{
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.InvalidArguments));
			}
			m_InputLength = inputLength;
			StringBuilder utf16OutPutBuilder = null;
			SetRequestObject(ref utf16OutPutBuilder, outputOwnedByClient: false, m_CsxOffset, buffer, (int)m_InputLength);
			DecodedText = string.Empty;
			ObxmlDecodeResponse obxmlDecodeResponse = Decode();
			if (obxmlDecodeResponse != null && (obxmlDecodeResponse.IsSuccess || obxmlDecodeResponse.IsDone))
			{
				DecodedText = utf16OutPutBuilder.ToString();
				HandleCompleteParse();
			}
			return DecodedText;
		}

		internal void HandleCompleteParse()
		{
			if (ObxmlDecodeContext.m_XMLTypeParseAllXml)
			{
				if (!string.IsNullOrEmpty(DecodedText))
				{
					if (ProviderConfig.m_bTraceLevelPrivate)
					{
						Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)16777472, OracleTraceClassName.ObxmlDecodeStream, OracleTraceFuncName.HandleCompleteParse, "DECODE Full Parse START context id" + base.ContextId + " time-stamp " + GetTimeStamp(isStart: true));
					}
					XDocument xDocument = XDocument.Parse(DecodedText);
					XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
					xmlWriterSettings.Indent = true;
					xmlWriterSettings.Encoding = Encoding.Unicode;
					StringBuilder stringBuilder = new StringBuilder(ObxmlDecodeContext.GetOutputLengthEstimate(DecodedText.Length, fullBufferEstimate: true));
					using (XmlWriter writer = XmlWriter.Create(stringBuilder, xmlWriterSettings))
					{
						xDocument.WriteTo(writer);
					}
					xDocument = null;
					DecodedText = stringBuilder.ToString();
					if (ProviderConfig.m_bTraceLevelPrivate)
					{
						Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)16777728, OracleTraceClassName.ObxmlDecodeStream, OracleTraceFuncName.HandleCompleteParse, "DECODE Full Parse Done context id" + base.ContextId + " time-stamp " + GetTimeStamp(isStart: false) + " CacheSize " + base.CacheSizeString + base.PerformanceCounterString + " Duration " + base.DecodeTimeStamp);
					}
				}
			}
			else if (ObxmlDecodeContext.m_XMLTypeParseXml && !string.IsNullOrEmpty(DecodedText) && base.DecodeState.PerformFullXmlParse)
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)16777472, OracleTraceClassName.ObxmlDecodeStream, OracleTraceFuncName.HandleCompleteParse, "DECODE Full Parse START context id" + base.ContextId + " time-stamp " + GetTimeStamp(isStart: true));
				}
				XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
				xmlReaderSettings.ConformanceLevel = ConformanceLevel.Document;
				xmlReaderSettings.DtdProcessing = DtdProcessing.Parse;
				xmlReaderSettings.ProhibitDtd = false;
				XmlReader xmlReader = XmlReader.Create(new StringReader(DecodedText), xmlReaderSettings);
				XmlWriterSettings xmlWriterSettings2 = new XmlWriterSettings();
				xmlWriterSettings2.Indent = true;
				xmlWriterSettings2.NamespaceHandling = NamespaceHandling.OmitDuplicates;
				xmlWriterSettings2.ConformanceLevel = ConformanceLevel.Document;
				xmlWriterSettings2.Encoding = Encoding.Unicode;
				StringBuilder stringBuilder2 = new StringBuilder(ObxmlDecodeContext.GetOutputLengthEstimate(DecodedText.Length, fullBufferEstimate: true));
				using (XmlWriter xmlWriter = XmlWriter.Create(stringBuilder2, xmlWriterSettings2))
				{
					xmlWriter.WriteNode(xmlReader, defattr: true);
				}
				xmlReader.Close();
				xmlWriterSettings2 = null;
				DecodedText = stringBuilder2.ToString();
				stringBuilder2 = null;
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)16777728, OracleTraceClassName.ObxmlDecodeStream, OracleTraceFuncName.HandleCompleteParse, "DECODE Full Parse Done context id" + base.ContextId + " time-stamp " + GetTimeStamp(isStart: false) + " CacheSize " + base.CacheSizeString + base.PerformanceCounterString + " Duration " + base.DecodeTimeStamp);
				}
			}
		}

		internal StringBuilder DecodeBlobForXmlStream(bool streamingCall = true)
		{
			if (m_Blob == null || !IsValid)
			{
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.InvalidArguments));
			}
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)16777472, OracleTraceClassName.ObxmlDecodeStream, OracleTraceFuncName.DecodeBlobForXmlStream, "DECODE BLOB START context id" + base.ContextId + " time-stamp " + GetTimeStamp(isStart: true));
			}
			byte[] array = ReadBlob(m_Blob.m_blobImpl);
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)16777728, OracleTraceClassName.ObxmlDecodeStream, OracleTraceFuncName.DecodeBlobForXmlStream, "DECODE BLOB START (buffer created) context id" + base.ContextId + " time-stamp " + GetTimeStamp(isStart: false) + " CacheSize " + base.CacheSizeString + base.PerformanceCounterString + " Duration " + base.DecodeTimeStamp);
			}
			m_InputLength = array.Length;
			StringBuilder utf16OutPutBuilder = null;
			SetRequestObject(ref utf16OutPutBuilder, streamingCall, m_CsxOffset, array, (int)(streamingCall ? m_InputLength : 0));
			ObxmlDecodeResponse obxmlDecodeResponse = Decode();
			if (obxmlDecodeResponse != null && (obxmlDecodeResponse.IsSuccess || obxmlDecodeResponse.IsDone))
			{
				return utf16OutPutBuilder;
			}
			return null;
		}

		internal string DecodeBlob()
		{
			StringBuilder stringBuilder = null;
			DecodedText = string.Empty;
			if ((stringBuilder = DecodeBlobForXmlStream(streamingCall: false)) != null)
			{
				DecodedText = stringBuilder.ToString();
				HandleCompleteParse();
			}
			return DecodedText;
		}
	}
}
